﻿using System.Windows;
using Prism.Events;
using Prism.Ioc;
using Module.Common.Common;
using Module.Common.PubEvent;
using Module.Common.Views.Marks;
using System.Windows.Controls;
using Module.Common.Interface;
using System.Windows.Documents;
using Module.Common.Common.QiPuHelper;
using System.Diagnostics;
using System.Windows.Markup;

namespace Module.Common.Views
{
    /// <summary>
    /// Interaction logic for CanJuPoJie
    /// </summary>
    public partial class ChessBoard : UserControl, IQiPanBase
    {
        private readonly IEventAggregator Ea;
        public string ModuleName { get; set; } // 模块名称，用于订阅消息过滤。很关键。
        public string ClassName { get; set; } // 类名称，用于跟踪订阅消息发出者。主要用于调试，对软件无实质作用。
        private bool SideTag;

        public ChessPieces[] PiecessArray = new ChessPieces[32]; // 棋子数组，所有棋子均在此数组中
        public MovePoint[,] MovePointArray = new MovePoint[9, 10]; // 可移动点实例数组。可移动点实例的作用，一是在棋盘上显示当前选中棋子可到达的位置，二是接收鼠标点击事件，发出点击位置信息，棋子接收后，移动到该位置。
        public int[,] ChessBoardData = new int[9, 10]; // 棋盘数据信息，记录整个棋盘上的棋子所在位置。为-1时，表示该位置没有棋子，为0-31时，表示该位置有棋子，数字是棋子的编号。

        public ChessBoard(IEventAggregator ea, IContainerProvider Cp, LastLocation lastLocation, CurrentLoaction currentLoaction, string moduleName)
        {
            InitializeComponent();
            this.Ea = ea;
            ModuleName = moduleName;
            ClassName = this.GetType().Name;
            Ea.GetEvent<SystemMessageEvent>().Subscribe(SystemMessageProcess);
            Ea.GetEvent<ServiceMessageEvent>().Subscribe(ServiceMessageProcess, ThreadOption.PublisherThread, false, filter => filter.ModuleName.Equals(ModuleName));
            Ea.GetEvent<ModuleMessageEvent>().Subscribe(ModuleMessageProcess, ThreadOption.PublisherThread, false, filter => filter.ModuleName.Equals(ModuleName));


            for (int i = 0; i < 9; i++)
                for (int j = 0; j < 10; j++)
                {
                    MovePointArray[i, j] = Cp.Resolve<MovePoint>(); // 棋盘上添加可移动点
                    MovePointArray[i, j].SetInitPosition(i, j);
                    movePointGrid.Children.Add(MovePointArray[i, j]);
                    MovePointArray[i, j].ModuleName = ModuleName;
                }
            for (int i = 0; i < 32; i++)
            {
                PiecessArray[i] = Cp.Resolve<ChessPieces>();// 棋盘上添加棋子
                PiecessArray[i].SetID(i); // 设置棋子编号
                qiZiGrid.Children.Add(PiecessArray[i]);
                //qiZiArray[i].SetInitPosition(); // 棋子放置到初始位置
                PiecessArray[i].ModuleName = ModuleName;
            }
            lastLocation.ModuleName = ModuleName;
            marksGrid.Children.Add(lastLocation);
            currentLoaction.ModuleName = ModuleName;
            marksGrid.Children.Add(currentLoaction);

            SideTag = GlobalData.REDSIDE;
        }
        #region 订阅消息处理
        /// <summary>
        /// 系统消息处理
        /// </summary>
        /// <param name="obj"></param>
        public void SystemMessageProcess(SystemMessage obj)
        {
            switch (obj.MessageName)
            {
               
                default:
                    break;
            }
        }
        public void ServiceMessageProcess(ServiceMessage obj)
        {
            switch (obj.MessageName)
            {
                case "BestMoveOk": 
                    break;
                default:
                    break;
            }

        }
        /// <summary>
        /// 模块消息处理
        /// </summary>
        /// <param name="obj">消息体</param>
        public void ModuleMessageProcess(ModuleMessage obj)
        {
            switch (obj.MessageName)
            {
                case "qiziGetClicked":  // 有棋子选中时，将棋子信息、棋盘数据发送给计算中心，计算其可移动路径
                    QiPanDataRefresh();
                    Ea.GetEvent<ServiceMessageEvent>().Publish(new ServiceMessage()
                    {
                        MessageName = "getMovePoint", // 发送获取可移动点消息。为什么不放在棋子类中？因为需要附加棋盘数据。
                        Id = obj.Id,
                        //NewCol = obj.NewCol,
                        //NewRow = obj.NewRow,
                        QiPanData_Message = ChessBoardData,
                        SenderFrom = ClassName,
                        Content = $"【{ClassName}】：请计算可移动点",
                        ModuleName = ModuleName
                    });
                    ReplyMessage(obj.MessageName);
                    break;


                case "qiziStartMove":
                    if (SideTag == GlobalData.BLACKSIDE && obj.Id < 16 || SideTag == GlobalData.REDSIDE && obj.Id >= 16) // 走棋方正确
                    {
                        QiPanDataRefresh();
                        // 修正棋盘数据。此处是为了解决如下问题：
                        // 如果目标位置有棋子，在本棋子开始移动时，尚未吃掉目标棋子，而检测将军状态使用的是棋子移动完毕后的棋盘数据。
                        // 因此，此处将棋盘数据的目标位置设置为正在移动的棋子。
                        ChessBoardData[obj.NewCol, obj.NewRow] = obj.Id;
                        ChessBoardData[obj.BufferCol, obj.BufferRow] = -1; // 原位置清空
                        Ea.GetEvent<ServiceMessageEvent>().Publish(new ServiceMessage()
                        {
                            MessageName = "checkJiangJun", // 棋子移动开始后，检查是否存在将军、绝杀、困毙等情况。
                            QiPanData_Message = ChessBoardData,
                            Id = obj.Id,
                            SenderFrom = ClassName,
                            Content = $"【{ClassName}】：请检查是否发生了将军、绝杀、困毙",
                            ModuleName = ModuleName
                        });
                    }
                    else // 走棋方错误
                    {
                        string errstr = (SideTag == GlobalData.REDSIDE) ? "红方" : "黑方";
                        string Messagetext = $"走棋方错误！应【{errstr}】走棋。";
                        Ea.GetEvent<ModuleMessageEvent>().Publish(new ModuleMessage()
                        {
                            MessageName = "moveSideError",
                            SenderFrom = ClassName,
                            ModuleName = ModuleName,
                            Content = Messagetext
                        });
                    }

                    ReplyMessage(obj.MessageName);
                    break;
                case "qiziLocationHasChanged":
                    #region 吃子处理
                    QiPanDataRefresh();
                    int dieQz = ChessBoardData[obj.NewCol, obj.NewRow];
                    if (dieQz >= 0)
                    {
                        PiecessArray[dieQz].Visibility = System.Windows.Visibility.Hidden; // 吃子
                    }
                    PiecessArray[obj.Id].CurCol = obj.NewCol;
                    PiecessArray[obj.Id].CurRow = obj.NewRow;
                    #endregion

                    Ea.GetEvent<ModuleMessageEvent>().Publish(new ModuleMessage()
                    {
                        MessageName = "updateQiPu", // 棋子移动后，更新棋谱。
                        Id = obj.Id,
                        BufferCol = obj.BufferCol,
                        BufferRow = obj.BufferRow,
                        NewCol = obj.NewCol,
                        NewRow = obj.NewRow,
                        DieQz = dieQz,
                        SenderFrom = ClassName,
                        Content = $"【{ClassName}】：走棋结束，请更新完全树棋谱",
                        ModuleName = ModuleName
                    });
                    QiPanDataRefresh();
                    //ChessBoardData[obj.NewCol, obj.NewRow] = obj.Id; // 修正棋盘数据
                    Ea.GetEvent<ServiceMessageEvent>().Publish(new ServiceMessage()
                    {
                        MessageName = "getBestStep", // 棋子移动后，计算下一步最佳着法。
                        QiPanData_Message = ChessBoardData,
                        SideTag = obj.Id < 16 ? GlobalData.REDSIDE : GlobalData.BLACKSIDE,
                        SenderFrom = ClassName,
                        Content = $"【{ClassName}】：请计算下一步最佳着法",
                        ModuleName = ModuleName
                    });
                    if (obj.Id < 16) SideTag = GlobalData.REDSIDE; // 棋子移动完毕，更换走棋方
                    else SideTag = GlobalData.BLACKSIDE;

                    ReplyMessage(obj.MessageName);
                    break;
                case "goBackStepLunch":
                    SideTag = !SideTag;
                    break;
                case "reStart": // 重新开局
                    //ReStart();
                    SideTag = GlobalData.REDSIDE;
                    ReplyMessage(obj.MessageName);
                    break;
                default: break;
            }
        }

        /// <summary>
        /// 接收到订阅消息后，做出应答。主要用于程序调试时的消息跟踪。
        /// </summary>
        /// <param name="messagetext"></param>
        private void ReplyMessage(string messagetext)
        {
            Ea.GetEvent<ReplyMessageEvent>().Publish(new ReplyMessage()
            {
                MessageName = "",
                SenderFrom = ClassName,
                Content = $"【{ClassName}】：已收到并处理了订阅消息【{messagetext}】",
                ModuleName = ModuleName,
            });
        }
        #endregion
        public void ReStart() { SideTag = GlobalData.REDSIDE; }

        /// <summary>
        /// 棋盘数据更新
        /// </summary>
        public void QiPanDataRefresh()
        {
            for (int i = 0; i < 9; i++)
                for (int j = 0; j < 10; j++)
                {
                    ChessBoardData[i, j] = -1;
                }
            for (int i = 0; i < 32; i++)
            {
                if (PiecessArray[i].IsVisible) ChessBoardData[PiecessArray[i].CurCol, PiecessArray[i].CurRow] = i; // 获取棋盘数据
            }
        }

        /// <summary>
        /// 设置棋子到默认位置
        /// </summary>
        public void SetPieceOnDefaultInitPosition()
        {
            for (int i = 0; i < 32; i++)
            {
                PiecessArray[i].SetDefaultInitPosition();
            }
            SideTag = GlobalData.REDSIDE;
        }

        /// <summary>
        /// 依据给定的棋盘局面数据，设置棋子到指定位置
        /// </summary>
        /// <param name="FenString">Fen格式棋盘局面数据</param>
        public void SetPieceOnAssignInitPosition(string FenString)
        {
            int[,] QiPanData = GlobalFunction.ConvertFenStrToQiPan(FenString);
            for (int i = 0; i < 32; i++)
            {
                PiecessArray[i].Visibility = Visibility.Hidden;
                PiecessArray[i].SetAssignInitPosition(-1, -1);
            }
            for (int i = 0; i <= 8; i++)
            {
                for (int j = 0; j <= 9; j++)
                {
                    int qizi = QiPanData[i, j];
                    if (qizi > -1)
                    {
                        PiecessArray[qizi].SetAssignInitPosition(i, j);
                    }
                }
            }
            SideTag = GlobalData.REDSIDE;
        }

    }
}
